package api

import (
	"context"
	"fmt"
	"github.com/dgrijalva/jwt-go"
	"github.com/gin-gonic/gin"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
	"net/http"
	"project05_web/src/forms"
	"project05_web/src/global"
	"project05_web/src/global/response"
	"project05_web/src/middlewares"
	"project05_web/src/models"
	"project05_web/src/proto"
	"project05_web/src/utils/login_tool"

	"project05_web/src/utils"
	"project05_web/src/utils/redis"
	"strconv"
	"time"
)

func SwitchGrpcErrorToHttp(err error, c *gin.Context) {
	if err != nil {
		if e, ok := status.FromError(err); ok {
			switch e.Code() {
			case codes.NotFound:
				c.JSON(http.StatusNotFound, gin.H{
					"msg": e.Message(),
				})
			case codes.Internal:
				c.JSON(http.StatusInternalServerError, gin.H{
					"msg": "内部错误",
				})
			case codes.InvalidArgument:
				c.JSON(http.StatusBadRequest, gin.H{
					"msg": "参数错误",
				})
			case codes.AlreadyExists:
				c.JSON(http.StatusBadRequest, gin.H{
					"msg": "用户已存在",
				})
			default:
				c.JSON(http.StatusInternalServerError, gin.H{
					"msg": "未知错误",
				})
			}
		}
	}
}

func GetUserList(c *gin.Context) {
	//服务发现
	//consulInfo := global.SrvConfig.ConsulInfo
	//cfg := api.DefaultConfig()
	//cfg.Address = fmt.Sprintf("%s:%d", consulInfo.Host, consulInfo.Port)
	//client, err := api.NewClient(cfg)
	//if err != nil {
	//	panic(err)
	//}
	//data, err := client.Agent().ServicesWithFilter(fmt.Sprintf(`Service=="%s"`, global.SrvConfig.UserSrv.Name))
	//if err != nil {
	//	panic(err)
	//}
	//srvHost := ""
	//srvPort := 0
	//for _, value := range data {
	//	srvHost = value.Address
	//	srvPort = value.Port
	//	break
	//}
	//if srvHost == "" {
	//	panic(err)
	//}

	userClient := global.UserClient

	pns := c.Query("pn")
	pn, err := strconv.Atoi(pns)
	if err != nil {
		fmt.Println("Atoi err", err)
		return
	}
	//pSizes := c.Param("psize")
	//pSize, err := strconv.Atoi(pSizes)

	if err != nil {
		SwitchGrpcErrorToHttp(err, c)
		return
	}

	res, err := userClient.GetUserList(context.Background(), &proto.PageInfo{
		Pn:    uint32(pn),
		PSize: 6,
	})
	if err != nil {
		SwitchGrpcErrorToHttp(err, c)
		return
	}

	result := make([]interface{}, 1)

	for _, user := range res.Date {
		userModel := response.UserResponse{
			UserId:   int(user.Id),
			UserName: user.UserName,
			Phone:    user.Phone,
			Name:     user.Name,
			Identify: user.Identify,
			RoleID:   int(user.RoleID),
		}

		result = append(result, userModel)
	}

	c.JSON(http.StatusOK, gin.H{
		"users": result,
		"total": res.Total,
	})
}

func GetUserByUserName(c *gin.Context) {
	//target := fmt.Sprintf("%s:%d", global.SrvConfig.UserSrv.Host, global.SrvConfig.UserSrv.Port)
	//conn, err := grpc.Dial(target, grpc.WithTransportCredentials(insecure.NewCredentials()))
	//if err != nil {
	//	fmt.Println("grpc.Dial err", err)
	//	return
	//}

	userName := c.DefaultQuery("userName", " ")

	userService := global.UserClient
	userRes, err := userService.GetUserByUserName(context.Background(), &proto.UserNameRequest{UserName: userName})
	if err != nil {
		SwitchGrpcErrorToHttp(err, c)
		return
	}

	result := response.UserResponse{
		UserName: userRes.UserName,
		Phone:    userRes.Phone,
		Name:     userRes.Name,
		Identify: userRes.Identify,
		RoleID:   int(userRes.RoleID),
	}

	c.JSON(http.StatusOK, gin.H{
		"data": result,
	})
}

func UpdatePassword(c *gin.Context) {
	userClient := global.UserClient

	var updateForm forms.UpdatePassword
	err := c.ShouldBind(&updateForm)
	if err != nil {
		c.JSON(http.StatusBadRequest, utils.ErrResp(err))
		return
	}

	_, err = userClient.UpdateUserPassword(context.Background(), &proto.UpdatePasswordRequest{
		Id:       int32(updateForm.UserId),
		Password: updateForm.Password,
	})
	if err != nil {
		SwitchGrpcErrorToHttp(err, c)
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"msg": "修改成功",
	})
}

func PasswordLogin(c *gin.Context) {
	//定义一个结构体
	passwordFrom := forms.PasswordLoginFrom{}
	//将请求映射到结构体当中
	err := c.ShouldBind(&passwordFrom)
	if err != nil {
		c.JSON(http.StatusBadRequest, utils.ErrResp(err))
		return
	}
	//所有请求变量
	Account := passwordFrom.Account
	CaptchaId := passwordFrom.CaptchaId
	Captcha := passwordFrom.Captcha
	ip := c.ClientIP()
	userService := global.UserClient
	//取出该ip的失败登录次数
	num, err_getip := global.RedisDb.Get(context.Background(), ip).Int()
	if err_getip != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"msg":  "系统错误",
			"code": 500,
		})
		return
	}
	if num > 10 { //如果大于10次那么返回手机登录
		c.JSON(http.StatusBadRequest, gin.H{
			"msg":  "登录尝试过多请用手机号登录",
			"code": 400,
		})
		return
	}
	//验证码校验，用完一次就销毁
	checkResult := store.Verify(CaptchaId, Captcha, true)
	if !checkResult { //验证码是否正确
		c.JSON(http.StatusBadRequest, gin.H{
			"msg":  "验证码错误",
			"code": 400,
		})
		return
	} else {
		//从redis里查CaptchaId是否有过期,如果没有过期ok,清缓存
		if !redis.ExistKey(Captcha) { //过期
			//返回400 验证码过期,登录失败
			c.JSON(http.StatusBadRequest, gin.H{
				"msg":  "验证码过期",
				"code": 400,
			})
			return
		}
	}
	//账号是否存在校验
	//前端的Uname解析为email
	//phone
	//uname
	//只要有一端查到就ok
	var flag = false
	user, err_getphone := userService.GetUserByPhone(context.Background(), &proto.PhoneRequest{Phone: Account})
	user, err_getemail := userService.GetUserByEmail(context.Background(), &proto.EmailRequest{Email: Account})
	user, err_Uname := userService.GetUserByUserName(context.Background(), &proto.UserNameRequest{UserName: Account})

	if err_getphone == nil || err_getemail == nil || err_Uname == nil {
		flag = true
	}
	if !flag {
		c.JSON(http.StatusBadRequest, gin.H{
			"msg":  "用户名不存在请注册",
			"code": 400,
		})
	}
	//校验密码是否正确
	checkRes, err := userService.CheckPassword(context.Background(), &proto.CheckPasswordInfo{
		Password:        passwordFrom.Password,
		EncryptPassword: user.Password,
	})

	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{
			"code": 500,
			"msg":  "内部异常",
		})
		return
	}

	if checkRes.Success {
		//取该用户上次登录的ip
		ip_last, err_ip := userService.GetUserLastIp(context.Background(), &proto.UserId{Id: user.Id})
		if err_ip != nil {
			c.JSON(http.StatusInternalServerError, gin.H{
				"code": 500,
				"msg":  "内部异常",
			})
			return
		}
		if !login_tool.Ip_is_Offsite(ip, ip_last.String()) { //异地
			c.JSON(http.StatusInternalServerError, gin.H{
				"code": 502,
				"msg":  "重定向到手机登录验证",
			})
			return
		}
		j := middlewares.NewJWT()
		claims := models.CustomClaims{
			ID:          uint(user.Id),
			UserName:    user.UserName,
			AuthorityId: uint(user.RoleID),
			StandardClaims: jwt.StandardClaims{
				ExpiresAt: time.Now().Unix() + 60*60*24*7, //设置7天jwt过期时间
				Issuer:    "Jo",
				NotBefore: time.Now().Unix(),
			},
		}
		token, err := j.CreateToken(claims) //发送token给前端
		if err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{
				"msg": "生成token失败",
			})
			return
		}
		fmt.Println("role", user.RoleID)
		c.JSON(http.StatusOK, gin.H{
			"code":       200,
			"msg":        "登录成功",
			"id":         user.Id,
			"username":   user.UserName,
			"role":       user.RoleID,
			"x_token":    token,
			"expired_at": (time.Now().Unix() + 60*60*24*30) * 1000,
		})
	} else {
		login_tool.Ip_loginfail(c.ClientIP())
		c.JSON(http.StatusBadRequest, gin.H{
			"password": "密码错误",
		})
	}
}
